﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Drawing;
using Microsoft.VisualBasic;
using System.IO;
using Microsoft.Win32;
using System.Diagnostics;

//Program class
static class Program
{
    static List<MyTimer> timers = new List<MyTimer>();
    static public Timer Tmr = new Timer();
    static MyTimer currentTimer = null;
    static public MyTimer CurrentTimer
    {
        get { return currentTimer; }
        set
        {
            if (currentTimer != null) currentTimer.Stop();
            if (value != null) value.Start();
            currentTimer = value;
        }
    }

    static void Main()
    {
        if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length > 1)
        {
            MessageBox.Show("An instance of Countup is already running. To create a new timer, right-click the existing timer and click 'New'.", "Countup");
            return;
        }
        Tmr.Interval = 1000;
        try
        {
            using (BinaryReader b = new BinaryReader(File.Open("timers", FileMode.Open)))
            {
                int tc = b.ReadInt32(); if (tc <= 0) throw new Exception();
                for (int i = 0; i < tc; i++)
                    timers.Add(new MyTimer(b));
            }
        }
        catch (Exception)
        {
            timers.Clear();
            AddTimer();
        }
        UpdateTransferMenu();
        SessionEndingEventHandler seHandler = (s, e) => FinishTimers();
        PowerModeChangedEventHandler pmHandler = (s, e) => { if (e.Mode == PowerModes.Suspend && CurrentTimer != null) CurrentTimer = null; };
        SystemEvents.SessionEnding += seHandler;
        SystemEvents.PowerModeChanged += pmHandler;
        Application.Run();
        SystemEvents.SessionEnding -= seHandler;
        SystemEvents.PowerModeChanged -= pmHandler;
    }

    static public void AddTimer()
    {
        timers.Add(new MyTimer(null));
        UpdateTransferMenu();
    }
    static public void DeleteTimer(MyTimer t)
    {
        t.Finish(null);
        timers.Remove(t);
        if (timers.Count == 0) { File.Delete("timers"); Application.Exit(); }
        UpdateTransferMenu();
    }
    static public void UpdateTransferMenu()
    {
        foreach (var timer in timers)
        {
            timer.MenuTransferDropDown.Items.Clear();
            foreach (var otherTimer in timers)
            {
                if (timer != otherTimer)
                {
                    timer.MenuTransferDropDown.Items.Add(otherTimer.Name, null, (s, e) =>
                    {
                        TimeSpan ts;
                        if (TimeSpan.TryParse(Microsoft.VisualBasic.Interaction.InputBox("Enter new time (h:m:s)", "Change Time", "00:00:00"), out ts))
                        {
                            if (timer.CurrentTime - ts < TimeSpan.Zero)
                                MessageBox.Show("You haven't got enough time to transfer this amount.", "Countup");
                            else
                            {
                                timer.AddTime(-ts);
                                otherTimer.AddTime(ts);
                            }
                        }
                    });
                }
            }
        }
    }
    static public void FinishTimers()
    {
        using (BinaryWriter b = new BinaryWriter(File.Open("timers", FileMode.Create)))
        {
            b.Write(timers.Count);
            foreach (MyTimer t in timers)
                t.Finish(b);
        }
    }
}

//MyTimer class
class MyTimer
{
    TimeSpan sofar = TimeSpan.Zero;
    DateTime oldtime;
    NotifyIcon nicon;
    public String Name = "#";
    Icon run, stop;
    ToolStripMenuItem menuName = new ToolStripMenuItem();
    ToolStripMenuItem menuTime = new ToolStripMenuItem();
    ToolStripMenuItem menuTransfer = new ToolStripMenuItem { Text = "Transfer to" };
    public ToolStripDropDown MenuTransferDropDown = new ToolStripDropDown();
    public TimeSpan CurrentTime
    {
        get { return Program.CurrentTimer == this ? DateTime.Now - oldtime + sofar : sofar; }
    }

    void UpdateTime(Object myObject, EventArgs myEventArgs) { UpdateTimeText(); }

    void UpdateTimeText()
    {
        menuName.Text = Name;
        menuTime.Text = CurrentTime.ToString(@"hh\:mm\:ss");
        nicon.Text = Name + ' ' + menuTime.Text;
    }

    void UpdateUI()
    {
        Bitmap b = new Bitmap(Countup.Properties.Resources.stop);
        Graphics g = Graphics.FromImage(b);
        g.DrawString(Name.Substring(0, 1), SystemFonts.DefaultFont, SystemBrushes.WindowText, 2.5f, 1);
        g.Flush();
        stop = Icon.FromHandle(b.GetHicon());
        b = new Bitmap(Countup.Properties.Resources.run);
        g = Graphics.FromImage(b);
        g.DrawString(Name.Substring(0, 1), SystemFonts.DefaultFont, SystemBrushes.WindowText, 2.5f, 1);
        g.Flush();
        run = Icon.FromHandle(b.GetHicon());
        nicon.Icon = Program.CurrentTimer == this ? run : stop;
        UpdateTimeText();
    }

    public MyTimer(BinaryReader bReader)
    {
        if (bReader != null)
        {
            Name = bReader.ReadString();
            sofar = new TimeSpan(bReader.ReadInt64());
        }
        nicon = new NotifyIcon(new System.ComponentModel.Container())
        {
            ContextMenuStrip = new ContextMenuStrip() { ShowCheckMargin = false, ShowImageMargin = false },
            Visible = true,
        };
        menuName.Click += (s, e) =>
        {
            string result = Microsoft.VisualBasic.Interaction.InputBox("Enter name", "Rename", Name).Trim();
            if (result != "") Name = result;
            UpdateUI();
            Program.UpdateTransferMenu();
        };
        nicon.ContextMenuStrip.Items.Add(menuName);
        menuTime.Click += (s, e) =>
        {
            TimeSpan ts;
            if (TimeSpan.TryParse(Microsoft.VisualBasic.Interaction.InputBox("Enter new time (h:m:s)", "Change Time",
                CurrentTime.ToString(@"hh\:mm\:ss")), out ts))
            {
                sofar = ts;
                oldtime = DateTime.Now;
                UpdateTimeText();
            }
        };
        nicon.ContextMenuStrip.Items.Add(menuTime);
        menuTransfer.DropDown = MenuTransferDropDown;
        nicon.ContextMenuStrip.Items.Add(menuTransfer);
        nicon.ContextMenuStrip.Items.Add("Reset", null, (x, y) =>
        {
            if (Program.CurrentTimer == this) Program.CurrentTimer = null;
            sofar = TimeSpan.Zero;
            UpdateTimeText();
        });
        nicon.ContextMenuStrip.Items.Add("Delete", null, (x, y) => { Program.DeleteTimer(this); });
        nicon.ContextMenuStrip.Items.Add(new ToolStripSeparator());
        nicon.ContextMenuStrip.Items.Add("New", null, (x, y) => { Program.AddTimer(); });
        nicon.ContextMenuStrip.Items.Add("Exit", null, (x, y) => { Program.FinishTimers(); Application.Exit(); });
        nicon.ContextMenuStrip.Items.Add("About", null, (x, y) => { MessageBox.Show("Created by Elliott Cymerman\n\n                  Freeware\n\n                  June 2012", "Countup"); });
        nicon.MouseClick += (x, y) => { if (y.Button == MouseButtons.Left) Program.CurrentTimer = (Program.CurrentTimer == this) ? null : this; };

        UpdateUI();
    }

    public void Start()
    {
        oldtime = DateTime.Now;
        Program.Tmr.Tick += UpdateTime;
        Program.Tmr.Start();
        nicon.Icon = run;
    }

    public void Stop()
    {
        UpdateTimeText();
        sofar += DateTime.Now - oldtime;
        Program.Tmr.Tick -= UpdateTime;
        Program.Tmr.Stop();
        nicon.Icon = stop;
    }

    public void AddTime(TimeSpan ts)
    {
        sofar += ts;
        UpdateTimeText();
    }

    public void Finish(BinaryWriter bWriter)
    {
        if (Program.CurrentTimer == this) Program.CurrentTimer = null;
        if (bWriter != null)
        {
            bWriter.Write(Name);
            bWriter.Write(sofar.Ticks);
        }
        nicon.Dispose();
    }

}